import * as THREE from 'three'

/**
 * 物理模拟器 - 实现力导向布局算法
 */
export class Simulator {
  constructor(renderer, graph) {
    this.renderer = renderer
    this.graph = graph
    
    // 模拟参数
    this.kValue = 100 // 弹簧常数
    this.damping = 0.9 // 阻尼
    this.timeStep = 0.016 // 时间步长
    
    // 力导向算法参数
    this.attractionForce = 0.1
    this.repulsionForce = 1000
    this.centeringForce = 0.01
    
    // 节点状态
    this.positions = null
    this.velocities = null
    this.forces = null
    this.nodeCount = 0
    
    // 边数据
    this.edgeIndices = null
    this.edgeCount = 0
    
    // 布局模式
    this.layoutMode = 'force'
    
    // 时间过滤
    this.timeMin = 0
    this.timeMax = Number.MAX_SAFE_INTEGER
    
    // GPU计算相关（如果需要）
    this.useGPU = false
    this.gpuCompute = null
  }

  /**
   * 初始化模拟器
   */
  init() {
    this.setupNodeData()
    this.setupEdgeData()
    this.initializePositions()
    this.initializeVelocities()
    this.initializeForces()
    
    console.log(`模拟器初始化完成: ${this.nodeCount} 节点, ${this.edgeCount} 边`)
  }

  /**
   * 设置节点数据
   */
  setupNodeData() {
    const nodes = Object.values(this.graph.nodes).sort((a, b) => a.id - b.id)
    this.nodeCount = nodes.length
    
    if (this.nodeCount === 0) {
      console.warn('没有节点数据')
      return
    }
  }

  /**
   * 设置边数据
   */
  setupEdgeData() {
    const edges = Object.values(this.graph.edges)
    const nodes = this.graph.nodes
    
    const validEdges = []
    
    edges.forEach(edge => {
      const sourceNode = nodes[edge.source]
      const targetNode = nodes[edge.target]
      
      if (sourceNode && targetNode) {
        validEdges.push([sourceNode.id, targetNode.id])
      }
    })
    
    this.edgeIndices = new Int32Array(validEdges.length * 2)
    this.edgeCount = validEdges.length
    
    validEdges.forEach((edge, index) => {
      this.edgeIndices[index * 2] = edge[0]
      this.edgeIndices[index * 2 + 1] = edge[1]
    })
  }

  /**
   * 初始化位置
   */
  initializePositions() {
    this.positions = new Float32Array(this.nodeCount * 3)
    
    // 根据布局模式初始化位置
    switch (this.layoutMode) {
      case 'circle':
        this.initCircleLayout()
        break
      case 'spiral':
        this.initSpiralLayout()
        break
      case 'cube':
        this.initCubeLayout()
        break
      default:
        this.initRandomLayout()
        break
    }
  }

  /**
   * 随机布局初始化
   */
  initRandomLayout() {
    for (let i = 0; i < this.nodeCount; i++) {
      this.positions[i * 3] = (Math.random() - 0.5) * 1000
      this.positions[i * 3 + 1] = (Math.random() - 0.5) * 1000
      this.positions[i * 3 + 2] = (Math.random() - 0.5) * 1000
    }
  }

  /**
   * 圆形布局初始化
   */
  initCircleLayout() {
    const radius = 500
    for (let i = 0; i < this.nodeCount; i++) {
      const angle = (i / this.nodeCount) * Math.PI * 2
      this.positions[i * 3] = Math.cos(angle) * radius
      this.positions[i * 3 + 1] = Math.sin(angle) * radius
      this.positions[i * 3 + 2] = 0
    }
  }

  /**
   * 螺旋布局初始化
   */
  initSpiralLayout() {
    const maxRadius = 800
    for (let i = 0; i < this.nodeCount; i++) {
      const t = i / this.nodeCount
      const angle = t * Math.PI * 10
      const radius = t * maxRadius
      this.positions[i * 3] = Math.cos(angle) * radius
      this.positions[i * 3 + 1] = Math.sin(angle) * radius
      this.positions[i * 3 + 2] = (t - 0.5) * 200
    }
  }

  /**
   * 立方体布局初始化
   */
  initCubeLayout() {
    const size = Math.ceil(Math.cbrt(this.nodeCount))
    const spacing = 100
    
    for (let i = 0; i < this.nodeCount; i++) {
      const x = i % size
      const y = Math.floor(i / size) % size
      const z = Math.floor(i / (size * size))
      
      this.positions[i * 3] = (x - size / 2) * spacing
      this.positions[i * 3 + 1] = (y - size / 2) * spacing
      this.positions[i * 3 + 2] = (z - size / 2) * spacing
    }
  }

  /**
   * 初始化速度
   */
  initializeVelocities() {
    this.velocities = new Float32Array(this.nodeCount * 3)
    // 初始速度为0
    this.velocities.fill(0)
  }

  /**
   * 初始化力
   */
  initializeForces() {
    this.forces = new Float32Array(this.nodeCount * 3)
  }

  /**
   * 更新模拟
   */
  update(deltaTime, temperature = 1) {
    if (!this.positions || !this.velocities || !this.forces) {
      return
    }

    // 重置力
    this.forces.fill(0)
    
    // 计算力
    this.calculateRepulsionForces()
    this.calculateAttractionForces()
    this.calculateCenteringForces()
    
    // 应用温度
    const tempFactor = Math.min(1, temperature / 100)
    
    // 更新速度和位置
    for (let i = 0; i < this.nodeCount; i++) {
      const idx = i * 3
      
      // 更新速度
      this.velocities[idx] += this.forces[idx] * deltaTime * tempFactor
      this.velocities[idx + 1] += this.forces[idx + 1] * deltaTime * tempFactor
      this.velocities[idx + 2] += this.forces[idx + 2] * deltaTime * tempFactor
      
      // 应用阻尼
      this.velocities[idx] *= this.damping
      this.velocities[idx + 1] *= this.damping
      this.velocities[idx + 2] *= this.damping
      
      // 更新位置
      this.positions[idx] += this.velocities[idx] * deltaTime
      this.positions[idx + 1] += this.velocities[idx + 1] * deltaTime
      this.positions[idx + 2] += this.velocities[idx + 2] * deltaTime
    }
  }

  /**
   * 计算斥力
   */
  calculateRepulsionForces() {
    for (let i = 0; i < this.nodeCount; i++) {
      for (let j = i + 1; j < this.nodeCount; j++) {
        const idx1 = i * 3
        const idx2 = j * 3
        
        const dx = this.positions[idx1] - this.positions[idx2]
        const dy = this.positions[idx1 + 1] - this.positions[idx2 + 1]
        const dz = this.positions[idx1 + 2] - this.positions[idx2 + 2]
        
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz) + 0.1 // 避免除零
        const force = this.repulsionForce / (distance * distance)
        
        const fx = (dx / distance) * force
        const fy = (dy / distance) * force
        const fz = (dz / distance) * force
        
        this.forces[idx1] += fx
        this.forces[idx1 + 1] += fy
        this.forces[idx1 + 2] += fz
        
        this.forces[idx2] -= fx
        this.forces[idx2 + 1] -= fy
        this.forces[idx2 + 2] -= fz
      }
    }
  }

  /**
   * 计算引力（基于边）
   */
  calculateAttractionForces() {
    for (let i = 0; i < this.edgeCount; i++) {
      const sourceIdx = this.edgeIndices[i * 2] * 3
      const targetIdx = this.edgeIndices[i * 2 + 1] * 3
      
      const dx = this.positions[targetIdx] - this.positions[sourceIdx]
      const dy = this.positions[targetIdx + 1] - this.positions[sourceIdx + 1]
      const dz = this.positions[targetIdx + 2] - this.positions[sourceIdx + 2]
      
      const distance = Math.sqrt(dx * dx + dy * dy + dz * dz) + 0.1
      const force = this.attractionForce * distance
      
      const fx = (dx / distance) * force
      const fy = (dy / distance) * force
      const fz = (dz / distance) * force
      
      this.forces[sourceIdx] += fx
      this.forces[sourceIdx + 1] += fy
      this.forces[sourceIdx + 2] += fz
      
      this.forces[targetIdx] -= fx
      this.forces[targetIdx + 1] -= fy
      this.forces[targetIdx + 2] -= fz
    }
  }

  /**
   * 计算中心化力
   */
  calculateCenteringForces() {
    for (let i = 0; i < this.nodeCount; i++) {
      const idx = i * 3
      
      this.forces[idx] -= this.positions[idx] * this.centeringForce
      this.forces[idx + 1] -= this.positions[idx + 1] * this.centeringForce
      this.forces[idx + 2] -= this.positions[idx + 2] * this.centeringForce
    }
  }

  /**
   * 获取当前位置
   */
  getPositions() {
    return this.positions
  }

  /**
   * 设置K值
   */
  setKValue(value) {
    this.kValue = value
    this.attractionForce = value * 0.001
  }

  /**
   * 重置模拟
   */
  reset() {
    this.initializePositions()
    this.initializeVelocities()
    if (this.forces) {
      this.forces.fill(0)
    }
  }

  /**
   * 设置布局模式
   */
  setLayoutMode(mode) {
    this.layoutMode = mode
    this.initializePositions()
    this.initializeVelocities()
  }

  /**
   * 设置时间范围
   */
  setTimeRange(min, max) {
    this.timeMin = min
    this.timeMax = max
    // 这里可以实现基于时间的边过滤
  }

  /**
   * 获取模拟统计信息
   */
  getStats() {
    if (!this.velocities) return null
    
    let totalKineticEnergy = 0
    for (let i = 0; i < this.nodeCount; i++) {
      const idx = i * 3
      const vx = this.velocities[idx]
      const vy = this.velocities[idx + 1]
      const vz = this.velocities[idx + 2]
      totalKineticEnergy += vx * vx + vy * vy + vz * vz
    }
    
    return {
      nodeCount: this.nodeCount,
      edgeCount: this.edgeCount,
      kineticEnergy: totalKineticEnergy,
      averageVelocity: Math.sqrt(totalKineticEnergy / this.nodeCount)
    }
  }

  /**
   * 销毁资源
   */
  dispose() {
    this.positions = null
    this.velocities = null
    this.forces = null
    this.edgeIndices = null
    
    if (this.gpuCompute) {
      this.gpuCompute.dispose()
    }
  }
}
